/* 
 * File:   Stack.h
 * Author: Gab'z
 *
 * Created on 27 mai 2012, 17:43
 */

#ifndef STACK_H
#define	STACK_H

#include <list>
#include "Constant.h"
#include "../../../exception/CommandException.h"
#include "../../../exception/ContextException.h"
#include "log/LogSystem.h"
#include "../../../tool/Observable.h"

namespace calculator {

    /**
     * Classe conteneur de Constant.
     * Utilise une liste pour pouvoir être parcourue,
     * Les modifications possible sont cependant limitées à celle d'une pile.
     * Une Stack peut être associée à un TabStackWidget, si une Stack subit une
     * modification, une mise à jour de la vue est automatiquement demandée
     */
    class Stack : public Observable {
        /**
         * Même remarque que pour StackList à propos de l'amitié avec XMLParser.
         * @see StackList.
         */
        friend class XMLParser;

    public:

        /**
         * Constructeur de Stack.
         * Crée une Stack vide.
         */
        Stack();

        /**
         * Destructeur de Stack.
         * Libère la mémoire occupée par les Constant que la Stack contient.
         */
        virtual ~Stack();

        /**
         * Nombre de Constant contenues dans la Stack.
         * @return le nombre de Constant contenues dans la Stack.
         */
        unsigned int size() const;

        /**
         * Clone la Stack et son contenu.
         * @return une copie de la Stack et des Constant qu'elle contient.
         */
        Stack* clone() const;

        /**
         * Getter vers la Constant désignée.
         * lance une ContextException si l'index sort de la pile.
         * index : [0 ; size() - 1].
         * @param n l'index de la Constant désirée parmi la Stack.
         * @return la Stack désignée.
         */
        const Constant* getConstant(unsigned int n) const throw (CommandException);

        /**
         * Empile une Constant en tête de la Stack.
         * @param constant la Constant à ajouter.
         */
        void push(const Constant* constant);

        /**
         * Getter vers la première Constant de la Stack.
         * @return la première Constant de la Stack, 0 si elle est vide.
         */
        const Constant* top() const;

        /**
         * Dépile la première Constant de la Stack si elle n'est pas vide.
         */
        void pop();

        /**
         * Vide la Stack de son contenu et libère la mémoire occupée par ce contenu.
         */
        void clear();

        /**
         * Indique si la Stack est vide ou non.
         * @return true si la Stack est vide, false sinon.
         */
        bool empty() const;

        /**
         * Echange les deux premières Constant de la Stack.
         */
        void swapTwoFirstConstant();

        /**
         * Echange les Constant désignées par leur index respectif.
         * Les index commencent à 0
         */
        void swapAnyConstant(const unsigned int pos1, const unsigned int pos2) throw (ContextException);

    private:
        
        /**
         * Conteneur de Constant
         */
        std::list<const Constant*> _constantStack;

        /**
         * Ecrase le pointeur de Constant désigné par l'index avec la Constant
         * Ne détruit pas l'actuelle Constant désignée de la Stack
         * @param constant la Constant qui remplacera celle de la Stack
         * @param n l'index de la Constant à remplacer
         */
        void setConstant(const Constant* constant, unsigned int n) throw (ContextException);

        static Logger* log;
    };

}
#endif	/* STACK_H */

